/*
 * TODO language 
 * Copyright (c) 2010 TODO Team
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <iostream>
#include <string>
#include <sstream>
#include "opcodes.h"

namespace todo
{
void TodoOpcodes::add(todo_opcode* opcode)
{
	opcode->op_num = get_num();
	list.push_back(opcode);
}

todo_opcode* TodoOpcodes::get_last(void)
{
	return list.back();
}

int TodoOpcodes::get_num(void) const
{
	return list.size();
}

todo_opcode* TodoOpcodes::get_opcode(unsigned int op_num)
{
	return ops.list[op_num];
}

void TodoOpcodes::dump_op(const TodoData& op) const
{
	std::cout << "Op: " << ops.get_value(op.data);
	if (op.type == TODO_VAR || op.type == TODO_CONSTANT) {
		std::cout << " (" << get_type(op) << ")" << std::endl;
	}
}

void TodoOpcodes::dump(todo_opcode*& op) const
{
	std::cout << "Opcode: " << ops.get_name(op->type) << std::endl;
	if (op->op1.type != TODO_UNUSED) {
		dump_op(op->op1);
	}		
	if (op->op2.type != TODO_UNUSED) {
		dump_op(op->op2);
	}
}

void TodoOpcodes::dump(void)
{
	std::vector<todo::todo_opcode*>::iterator it;
	
	for (it = list.begin(); it != list.end(); ++it) {
		dump(*it);
	}
}

void TodoOpcodes::free(void)
{
	std::vector<todo::todo_opcode*>::iterator it;
	
	for (it = list.begin(); it != list.end(); ++it) {
		delete *it;
	}
}

const std::string TodoOpcodes::get_name(todo_op_type type) const
{
	switch (type) {
		case TODO_ASSIGN:    return "ASSIGN";
		case TODO_PRINT:     return "PRINT";
		case TODO_DECL_VAR:  return "DECL_VAR";
		case TODO_DECL_FUNC: return "DEL_FUNC";
		case TODO_DECL_NS:   return "DECL_NS";
		case TODO_CHG_VAR:   return "CHG_VAR";
	}
	return "<UNKOWN>";
}

const std::string TodoOpcodes::get_value(const TodoValue& value) const
{
	std::stringstream s;
		
	switch (value.type) {
		case TODO_STRING:
			return *value.val.str;
		case TODO_INTEGER:
		case TODO_BOOL: 
			s << value.val.tint;
			return s.str();
		case TODO_DOUBLE: 
			s << value.val.tdouble;
			return s.str();
	}
	return "<UNKNOWN>";
}

const std::string TodoOpcodes::get_type(const TodoData& value) const
{
	switch (value.data.type) {
		case TODO_STRING:  return "string";
		case TODO_BOOL:    return "bool";
		case TODO_INTEGER: return "integer";
		case TODO_DOUBLE:  return "double";
	}
	return "<UNKNOWN>";
}

// Free specific info data
void todo_opcode::free_info(void)
{
	switch (type) {
		case TODO_FUNC_CALL:
			delete (todo_func_call*)info;
			break;
		case TODO_DECL_FUNC:
			((TodoFunction*)info)->args.clear();
			delete (TodoFunction*)info;
			break;
	}
}
} // todo
